package com.sx.medicinecard.config;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.sx.medicinecard.entity.LogData;
import com.sx.medicinecard.utils.AliLogUtils;
import com.sx.medicinecard.utils.IPUtils;
import com.sx.medicinecard.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class LoggingAspect {

    private final ThreadLocal<LogData> logDataThreadLocal = new ThreadLocal<>();

    @Autowired
    private AliLogUtils aliLogUtils;

    @Pointcut("execution(* com.sx.medicinecard.controller.*.*(..))")
    public void controllerMethods() {
    }

    @Before("controllerMethods()&&!execution(* com.sx.medicinecard.controller.AlipayCallbackController.*(..))")
//    @Before("controllerMethods()")
    public void logBefore(JoinPoint joinPoint) {
        // 获取HttpServletRequest对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;

        if (request == null) {
            throw new IllegalStateException("HttpServletRequest is not available");
        }

        // 获取应用的上下文路径
        String contextPath = request.getContextPath();

        // 获取请求的相对路径
        String relativePath = request.getRequestURI().substring(contextPath.length());

        // 获取请求的IP
        String ip = IPUtils.getRequestIP(request); // 获取IP的逻辑;

        // 获取请求名称
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上的@ApiOperation注解
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        String requestName = apiOperation != null ? apiOperation.value() : "";

        String phoneNo = "";

        JSONObject json = new JSONObject();
        String jsonString = "";

        String requestMethod = request.getMethod();
        // 获取传入参数
        Object[] args = joinPoint.getArgs();

        if ("GET".equalsIgnoreCase(requestMethod)) {
            // 获取GET请求的参数
            Map<String, String[]> requestMap = request.getParameterMap();
            for (Map.Entry<String, String[]> entry : requestMap.entrySet()) {
                json.put(entry.getKey(), entry.getValue()[0]);
            }
            jsonString = json.toJSONString();
        } else if ("POST".equalsIgnoreCase(requestMethod)) {
            // 获取POST请求的参数
            jsonString = Arrays.toString(args);
        }

        String userName = "";
        String token = request.getHeader("Authorization");
        if (ObjectUtil.isNotEmpty(token)) {
            Claims claims = JwtUtil.parseJWT(token);
            userName = "渠道编码为："+claims.get("channelCode")+",用户名称："+claims.get("userName");
        }
        log.info(requestName + ",传参：" + jsonString);

        LogData logData = new LogData();
        logData.setIp(ip);
        logData.setUrl(relativePath);
        logData.setUrlName(requestName);
        logData.setPhoneNo(StringUtils.isBlank(phoneNo) ?userName:phoneNo);
        logData.setRequestBody(jsonString);
        logDataThreadLocal.set(logData);
    }

    @AfterReturning(pointcut = "controllerMethods()&&!execution(* com.sx.medicinecard.controller.AlipayCallbackController.*(..))", returning = "result")
//    @AfterReturning(pointcut = "controllerMethods()",returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {

        LogData logData = logDataThreadLocal.get();

        String responseBody = "";
        if (!(result instanceof String)) {
            // 如果obj不是String类型，尝试将其转换为JSONObject
            try {
                responseBody = JSONObject.toJSON(result).toString();
                // 这里处理转换成功的情况
            } catch (Exception e) {
                // 这里处理转换失败的情况
            }
        } else {
            responseBody = result.toString();
        }

        log.info(logData.getUrlName() + ",返回参数：" + responseBody);
        aliLogUtils.pushLogToAli(logData.getIp(), logData.getUrl(), logData.getPhoneNo(), logData.getUrlName(), logData.getRequestBody(), responseBody);
        logDataThreadLocal.remove();
    }

    @Before("execution(* com.sx.medicinecard.controller.AlipayCallbackController.*(..)) && args(request,..)")
    public void logCallBack(JoinPoint joinPoint, HttpServletRequest request) {
        // 获取方法参数
        Map<String, String[]> requestMap = request.getParameterMap();
        JSONObject callBackJson = new JSONObject();

        for (Map.Entry<String, String[]> entry : requestMap.entrySet()) {
            callBackJson.put(entry.getKey(), entry.getValue()[0]);
        }
        String phoneNo = "";

        // 获取请求名称
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上的@ApiOperation注解
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        String requestName = apiOperation != null ? apiOperation.value() : "";

        log.info(requestName + ",传参：" + callBackJson.toJSONString());
        // 记录日志或其他处理

        // 获取请求的IP
        String ip = IPUtils.getRequestIP(request);
        // 获取应用的上下文路径
        String contextPath = request.getContextPath();
        // 获取请求的相对路径
        String relativePath = request.getRequestURI().substring(contextPath.length());
        String userName = "";
        String token = request.getHeader("Authorization");
        if (ObjectUtil.isNotEmpty(token)) {
            Claims claims = JwtUtil.parseJWT(token);
            userName = "用户名称："+claims.get("userName").toString()+",渠道编码为："+claims.get("channelCode").toString();
        }
        LogData logData = new LogData();
        logData.setIp(ip);
        logData.setUrl(relativePath);
        logData.setUrlName(requestName);
        logData.setPhoneNo(phoneNo);
        logData.setRequestBody(callBackJson.toJSONString());
        logDataThreadLocal.set(logData);
    }

    @AfterReturning(pointcut = "execution(* com.sx.medicinecard.controller.AlipayCallbackController.*(..))", returning = "result")
    public void logCallBackAfter(JoinPoint joinPoint, Object result) {

        LogData logData = logDataThreadLocal.get();

        String responseBody = "";
        if (!(result instanceof String)) {
            // 如果obj不是String类型，尝试将其转换为JSONObject
            try {
                responseBody = JSONObject.toJSON(result).toString();
                // 这里处理转换成功的情况
            } catch (Exception e) {
                // 这里处理转换失败的情况
            }
        } else {
            responseBody = result.toString();
        }

        log.info(logData.getUrlName() + ",返回参数：" + responseBody);
        aliLogUtils.pushLogToAli(logData.getIp(), logData.getUrl(), logData.getPhoneNo(), logData.getUrlName(), logData.getRequestBody(), responseBody);
        logDataThreadLocal.remove();
    }
}

